﻿Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.ComponentModel
Imports System.ComponentModel.Design

Public Class RadialGauge
#Region "Defaults"
    Private def_StartAngle As Single = 120
    Private def_Sweep As Single = 300
    Private def_RangeStart As Double = 0
    Private def_RangeEnd As Double = 100
    Private def_GaugeValue As Double = 0

    Private def_AxisColor As Color = Color.Blue
    Private def_AxisThickness As Integer = 3

    Private def_HT1_Width As Single = 10
    Private def_HT1_RangeStart As Double = 0
    Private def_HT1_RangeEnd As Double = 20
    Private def_HT1_Color As Color = Color.SkyBlue

    Private def_HT2_Width As Single = 10
    Private def_HT2_RangeStart As Double = 20
    Private def_HT2_RangeEnd As Double = 80
    Private def_HT2_Color As Color = Color.PaleGoldenrod

    Private def_HT3_Width As Single = 20
    Private def_HT3_RangeStart As Double = 80
    Private def_HT3_RangeEnd As Double = 100
    Private def_HT3_Color As Color = Color.Red
#End Region

#Region "Private Attributes"
    Private WithEvents _Background As New BackgroundType(Me)
    Private WithEvents _DialBackground As New DialBackgroundType()
    Private WithEvents _HT1 As New HeatArc(def_HT1_Width, def_HT1_RangeStart, def_HT1_RangeEnd, def_HT1_Color)
    Private WithEvents _HT2 As New HeatArc(def_HT2_Width, def_HT2_RangeStart, def_HT2_RangeEnd, def_HT2_Color)
    Private WithEvents _HT3 As New HeatArc(def_HT3_Width, def_HT3_RangeStart, def_HT3_RangeEnd, def_HT3_Color)
    Private WithEvents _MajorLabels As New MajorLabelsType()
    Private WithEvents _MajorTicks As New MajorTicksType()
    Private WithEvents _MinorTicks As New MinorTicksType()
    Private WithEvents _Needle As New NeedleType()

    Private _StartAngle As Single = def_StartAngle
    Private _Sweep As Single = def_Sweep
    Private _RangeStart As Double = def_RangeStart
    Private _RangeEnd As Double = def_RangeEnd
    Private _GaugeValue As Double = 0
    Private _PrevGaugeValue As Double = _GaugeValue

    Private _AxisColor As Color = def_AxisColor
    Private _AxisThickness As Integer = def_AxisThickness
#End Region

#Region "Public Enumerations"
    
#End Region

#Region "Public Interface"
    Public Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Me.SetStyle(ControlStyles.ResizeRedraw, True)
        Me.SetStyle(ControlStyles.UserPaint, True)
        SetTransparencyMode(False)
        Me.Size = New Size(200, 200)
    End Sub

    <Category("Appearance"), TypeConverter(GetType(BackgroundTypeConverter))> _
  Public Property Background() As BackgroundType
        Get
            Return _Background
        End Get
        Set(ByVal value As BackgroundType)
            _Background = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetBackground()
        _Background.Reset()
    End Sub
    Public Function ShouldSerializeBackground() As Boolean
        Return _Background.ShouldSerialize()
    End Function

    <Category("Appearance"), TypeConverter(GetType(DialBackgroundTypeConverter)), Description("Dial background properties.")> _
 Public Property DialBackground() As DialBackgroundType
        Get
            Return _DialBackground
        End Get
        Set(ByVal value As DialBackgroundType)
            _DialBackground = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetDialBackground()
        _DialBackground.Reset()
    End Sub
    Public Function ShouldSerializeDialBackground() As Boolean
        Return _DialBackground.ShouldSerialize()
    End Function


    <Category("Appearance"), TypeConverter(GetType(HeatArcTypeConverter)), Description("Heat Arc 1 style. Set Width=0 to hide it.")> _
    Public Property HeatArc1() As HeatArc
        Get
            Return _HT1
        End Get
        Set(ByVal value As HeatArc)
            _HT1 = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetHeatArc1()
        _HT1.Reset()
    End Sub
    Public Function ShouldSerializeHeatArc1() As Boolean
        Return _HT1.ShouldSerialize()
    End Function

    <Category("Appearance"), TypeConverter(GetType(HeatArcTypeConverter)), Description("Heat Arc 2 style. Set Width=0 to hide it.")> _
   Public Property HeatArc2() As HeatArc
        Get
            Return _HT2
        End Get
        Set(ByVal value As HeatArc)
            _HT2 = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetHeatArc2()
        _HT2.Reset()
    End Sub
    Public Function ShouldSerializeHeatArc2() As Boolean
        Return _HT2.ShouldSerialize()
    End Function

    <Category("Appearance"), TypeConverter(GetType(HeatArcTypeConverter)), Description("Heat Arc 3 style. Set Width=0 to hide it.")> _
    Public Property HeatArc3() As HeatArc
        Get
            Return _HT3
        End Get
        Set(ByVal value As HeatArc)
            _HT3 = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetHeatArc3()
        _HT3.Reset()
    End Sub
    Public Function ShouldSerializeHeatArc3() As Boolean
        Return _HT3.ShouldSerialize()
    End Function

    <Category("Appearance"), TypeConverter(GetType(MajorLabelsTypeConverter)), Description("Major Label styling.")> _
    Public Property MajorLabels() As MajorLabelsType
        Get
            Return _MajorLabels
        End Get
        Set(ByVal value As MajorLabelsType)
            _MajorLabels = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetMajorLabels()
        _MajorLabels.Reset()
    End Sub
    Public Function ShouldSerializeMajorLabels() As Boolean
        Return _MajorLabels.ShouldSerialize()
    End Function

    <Category("Appearance"), TypeConverter(GetType(MajorTicksTypeConverter)), Description("Major Ticks")> _
    Public Property MajorTicks() As MajorTicksType
        Get
            Return _MajorTicks
        End Get
        Set(ByVal value As MajorTicksType)
            _MajorTicks = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetMajorTicks()
        _MajorTicks.Reset()
    End Sub
    Public Function ShouldSerializeMajorTicks() As Boolean
        Return _MajorTicks.ShouldSerialize()
    End Function

    <Category("Appearance"), TypeConverter(GetType(MinorTicksTypeConverter)), Description("Minor Ticks")> _
    Public Property MinorTicks() As MinorTicksType
        Get
            Return _MinorTicks
        End Get
        Set(ByVal value As MinorTicksType)
            _MinorTicks = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetMinorTicks()
        _MinorTicks.Reset()
    End Sub
    Public Function ShouldSerializeMinorTicks() As Boolean
        Return _MinorTicks.ShouldSerialize()
    End Function

    <Category("Appearance"), TypeConverter(GetType(NeedleTypeConverter)), Description("Gauge Needle")> _
    Public Property Needle() As NeedleType
        Get
            Return _Needle
        End Get
        Set(ByVal value As NeedleType)
            _Needle = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetNeedle()
        _Needle.Reset()
    End Sub
    Public Function ShouldSerializeNeedle() As Boolean
        Return _Needle.ShouldSerialize()
    End Function

    <Category("Gauge"), Description("Value of Gauge.")> _
    Public Property Value() As Double
        Get
            Return _GaugeValue
        End Get
        Set(ByVal value As Double)
            _PrevGaugeValue = _GaugeValue
            _GaugeValue = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetValue()
        Me.Value = def_GaugeValue
    End Sub
    Public Function ShouldSerializeValue() As Boolean
        Return Not (Me.Value.Equals(def_GaugeValue))
    End Function

    <Category("Appearance"), Description("Starting angle in degrees for gauge. (0-360 measured counter clockwise)")> _
    Public Property StartAngle() As Single
        Get
            Return _StartAngle
        End Get
        Set(ByVal value As Single)
            If value < 0 OrElse value > 360 Then
                Throw New Exception("Invalid value. Angle must be in the range 0 - 360.")
            Else
                _StartAngle = value
                Me.Invalidate()
            End If
        End Set
    End Property
    Public Sub ResetStartAngle()
        Me.StartAngle = def_StartAngle
    End Sub
    Public Function ShouldSerializeStartAngle() As Boolean
        Return Not (StartAngle.Equals(def_StartAngle))
    End Function

    <Category("Appearance"), Description("The sweep represents the number of degrees the gauge uses on a 0-360 dial. (must <= 360)")> _
    Public Property Sweep() As Single
        Get
            Return _Sweep
        End Get
        Set(ByVal value As Single)
            If value > 360 Then
                Throw New Exception("Invalid value. Sweep must be <= 360.")
            Else
                _Sweep = value
                Me.Invalidate()
            End If
        End Set
    End Property
    Public Sub ResetSweep()
        Me.Sweep = def_Sweep
    End Sub
    Public Function ShouldSerializeSweep() As Boolean
        Return Not (Sweep.Equals(def_Sweep))
    End Function

    <Category("Gauge"), Description("Represents the start value of the dial scale.")> _
    Public Property RangeStart() As Double
        Get
            Return _RangeStart
        End Get
        Set(ByVal value As Double)
            _RangeStart = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetRangeStart()
        Me.RangeStart = def_RangeStart
    End Sub
    Public Function ShouldSerializeRangeStart() As Boolean
        Return Not (RangeStart.Equals(def_RangeStart))
    End Function

    <Category("Gauge"), Description("Represents the end vaue of the dial scale.")> _
    Public Property RangeEnd() As Double
        Get
            Return _RangeEnd
        End Get
        Set(ByVal value As Double)
            _RangeEnd = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetRangeEnd()
        Me.RangeEnd = def_RangeEnd
    End Sub
    Public Function ShouldSerializeRangeEnd() As Boolean
        Return Not (RangeEnd.equals(def_RangeEnd))
    End Function

    <Category("Appearance"), Description("The color of the dial's outer rim (axis) line.")> _
    Public Property AxisColor() As Color
        Get
            Return _AxisColor
        End Get
        Set(ByVal value As Color)
            _AxisColor = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetAxisColor()
        Me.AxisColor = def_AxisColor
    End Sub
    Public Function ShouldSerializeAxisColor() As Boolean
        Return Not (AxisColor.equals(def_AxisColor))
    End Function

    <Category("Appearance"), Description("The thickness of the dial's outer rim (axis) line.")> _
    Public Property AxisThickness() As Integer
        Get
            Return _AxisThickness
        End Get
        Set(ByVal value As Integer)
            _AxisThickness = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetAxisThickness()
        Me.AxisThickness = def_AxisThickness
    End Sub
    Public Function ShouldSerializeAxisThickness() As Boolean
        Return Not (AxisThickness.equals(def_AxisThickness))
    End Function
#End Region

#Region "Hidden Properties"
    <Browsable(False)> _
    Shadows Property BackgroundImage() As Color
        Get
        End Get
        Set(ByVal value As Color)
        End Set
    End Property
    <Browsable(False)> _
    Shadows Property BackgroundImageLayout() As Color
        Get
        End Get
        Set(ByVal value As Color)
        End Set
    End Property

    <Browsable(False)> _
    Shadows Property BackColor() As Color
        Get
        End Get
        Set(ByVal value As Color)
        End Set
    End Property

    <Browsable(False)> _
    Shadows Property Text() As String
        Get
            Return Nothing
        End Get
        Set(ByVal value As String)
        End Set
    End Property

#End Region

#Region "Paint Overrides"
    'Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
    '    MyBase.OnPaint(e)

    '    'Add your custom paint code here
    '    'Graphics
    '    Dim G As Graphics = e.Graphics
    '    G.SmoothingMode = Drawing2D.SmoothingMode.HighQuality


    '    'Bounding Rectangle of Control
    '    Dim ContainerRect As Rectangle = Me.ClientRectangle

    '    'Pixels needed to accomodate Major Labels
    '    Dim MajorLabelGap As Single = 0
    '    Dim TextHeight As Single = 0
    '    If _DisplayMajorLabels AndAlso _MajorLabelPosition = MajorLabelPositions.Outside Then
    '        TextHeight = G.MeasureString("1234567890", Me.Font).Height
    '        MajorLabelGap = _MajorLabelsPadding + TextHeight / 2
    '    Else
    '        'No gap needed
    '        MajorLabelGap = 0
    '        TextHeight = 0
    '    End If


    '    'Bounding Rectangle of Dial
    '    Dim BoundSize As Single = Math.Min(ContainerRect.Width, ContainerRect.Height) - 4
    '    Dim BoundX As Single = ContainerRect.X + (ContainerRect.Width - BoundSize) / 2
    '    Dim BoundY As Single = ContainerRect.Y + (ContainerRect.Height - BoundSize) / 2
    '    Dim DialRect As New RectangleF(BoundX, BoundY, BoundSize, BoundSize)

    '    'Dial Center Pt
    '    Dim DialCenterPt As New PointF(DialRect.X + DialRect.Width / 2, DialRect.Y + DialRect.Height / 2)

    '    'Dial Major Label Radius
    '    Dim MajorLabelRadius As Single = BoundSize / 2 - TextHeight / 2

    '    'Dial Outer Radius
    '    Dim DialOuterRadius As Single = MajorLabelRadius - MajorLabelGap


    '    Dim NeedleRadius As Single = _NeedlePercentageLength * DialOuterRadius / 100


    '    'Draw needle from Prev Value to Current Value
    '    DrawNeedle(DialCenterPt, NeedleRadius, NeedleAngle(_GaugeValue, _RangeStart, _RangeEnd, _StartAngle, _Sweep), _NeedleColor, _NeedleThickness, _NeedleCenterRadius, _NeedleCenterColor, G)

    '    'Draw Highlights
    '    'DrawDialHighlight(DialCenterPt, HeatArcInnerRadius, G)
    'End Sub

    'Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
    '    MyBase.OnPaintBackground(pevent)

    '    'Graphics
    '    Dim G As Graphics = pevent.Graphics
    '    G.SmoothingMode = Drawing2D.SmoothingMode.HighQuality

    '    'Draw Gauge background 
    '    If _Background.FillStyle = BackgroundType.FillStyles.Gradient Then
    '        Dim myBrush As LinearGradientBrush
    '        myBrush = New LinearGradientBrush(Me.ClientRectangle, _Background.BackColor1, _Background.BackColor2, Me._Background.FillGradientStyle)
    '        G.FillRectangle(myBrush, Me.ClientRectangle)
    '    Else
    '        G.FillRectangle(New SolidBrush(_Background.BackColor1), Me.ClientRectangle)
    '    End If


    '    'Bounding Rectangle of Control
    '    Dim ContainerRect As Rectangle = Me.ClientRectangle

    '    'Pixels needed to accomodate Major Labels
    '    Dim MajorLabelGap As Single = 0
    '    Dim TextHeight As Single = 0
    '    If _DisplayMajorLabels AndAlso _MajorLabelPosition = MajorLabelPositions.Outside Then
    '        TextHeight = G.MeasureString("1234567890", Me.Font).Height
    '        MajorLabelGap = _MajorLabelsPadding + TextHeight / 2
    '    Else
    '        'No gap needed
    '        MajorLabelGap = 0
    '        TextHeight = 0
    '    End If


    '    'Bounding Rectangle of Dial
    '    Dim BoundSize As Single = Math.Min(ContainerRect.Width, ContainerRect.Height) - 4
    '    Dim BoundX As Single = ContainerRect.X + (ContainerRect.Width - BoundSize) / 2
    '    Dim BoundY As Single = ContainerRect.Y + (ContainerRect.Height - BoundSize) / 2
    '    Dim DialRect As New RectangleF(BoundX, BoundY, BoundSize, BoundSize)

    '    'Dial Center Pt
    '    Dim DialCenterPt As New PointF(DialRect.X + DialRect.Width / 2, DialRect.Y + DialRect.Height / 2)

    '    'Dial Major Label Radius
    '    Dim MajorLabelRadius As Single = BoundSize / 2 - TextHeight / 2

    '    'Dial Outer Radius
    '    Dim DialOuterRadius As Single = MajorLabelRadius - MajorLabelGap

    '    'Major Tick - Inner/OuterRadii
    '    Dim MajorTickOuterRadius As Single = DialOuterRadius
    '    Dim MajorTickInnerRadius As Single = DialOuterRadius - _MajorTickSize

    '    'Minor Tick - Inner/Outer Radii
    '    Dim MinorTickOuterRadius As Single = DialOuterRadius
    '    Dim MinorTickInnerRadius As Single = DialOuterRadius - _MinorTickSize

    '    'Heat Arcs - Inner/Outer Radii
    '    Dim HeatArcOuterRadius As Single = DialOuterRadius
    '    Dim HeatArcInnerRadius As Single = HeatArcOuterRadius - Math.Min(Math.Min(_HT1.Width, _HT2.Width), _HT3.Width)



    '    'Draw Dial Background
    '    DrawDialBackground(DialCenterPt, DialOuterRadius - _AxisThickness, HeatArcInnerRadius, _StartAngle, _Sweep, _
    '                       _DialBackground.BackColor1, _DialBackground.BackColor2, _DialBackground.FillStyle, _
    '                       _DialBackground.FillGradientStyle, _NeedleCenterRadius, _DialBackground.DialStyle, G)


    '    'Draw Heat Arcs
    '    Dim StartAngle As Single
    '    Dim EndAngle As Single
    '    Dim InnerRadius As Single

    '    'HT1
    '    If _HT1.Width > 0 Then
    '        If _HT1.RangeStart <= _RangeStart Then
    '            StartAngle = _StartAngle
    '        Else
    '            StartAngle = Me.NeedleAngle(_HT1.RangeStart, _RangeStart, _RangeEnd, _StartAngle, _Sweep)
    '        End If
    '        If _HT1.RangeEnd >= _RangeEnd Then
    '            EndAngle = _StartAngle + _Sweep
    '        Else
    '            EndAngle = NeedleAngle(_HT1.RangeEnd, _RangeStart, _RangeEnd, _StartAngle, _Sweep)
    '        End If
    '        InnerRadius = HeatArcOuterRadius - _HT1.Width
    '        DrawFilledArcSegment(DialCenterPt, InnerRadius, HeatArcOuterRadius, StartAngle, EndAngle, _HT1.Color, G)
    '    End If

    '    'HT2
    '    If _HT2.Width > 0 Then
    '        If _HT2.RangeStart <= _RangeStart Then
    '            StartAngle = _StartAngle
    '        Else
    '            StartAngle = Me.NeedleAngle(_HT2.RangeStart, _RangeStart, _RangeEnd, _StartAngle, _Sweep)
    '        End If
    '        If _HT2.RangeEnd >= _RangeEnd Then
    '            EndAngle = _StartAngle + _Sweep
    '        Else
    '            EndAngle = NeedleAngle(_HT2.RangeEnd, _RangeStart, _RangeEnd, _StartAngle, _Sweep)
    '        End If
    '        InnerRadius = HeatArcOuterRadius - _HT2.Width
    '        DrawFilledArcSegment(DialCenterPt, InnerRadius, HeatArcOuterRadius, StartAngle, EndAngle, _HT2.Color, G)
    '    End If

    '    'HT3
    '    If _HT3.Width > 0 Then
    '        If _HT3.RangeStart <= _RangeStart Then
    '            StartAngle = _StartAngle
    '        Else
    '            StartAngle = Me.NeedleAngle(_HT3.RangeStart, _RangeStart, _RangeEnd, _StartAngle, _Sweep)
    '        End If
    '        If _HT3.RangeEnd >= _RangeEnd Then
    '            EndAngle = _StartAngle + _Sweep
    '        Else
    '            EndAngle = NeedleAngle(_HT3.RangeEnd, _RangeStart, _RangeEnd, _StartAngle, _Sweep)
    '        End If
    '        InnerRadius = HeatArcOuterRadius - _HT3.Width
    '        DrawFilledArcSegment(DialCenterPt, InnerRadius, HeatArcOuterRadius, StartAngle, EndAngle, _HT3.Color, G)
    '    End If


    '    'Draw Major/Minor Tick Marks
    '    Dim MajorTickAngleStep As Single = _Sweep / _NumMajorTicks
    '    Dim MinorTickAngleStep As Single = MajorTickAngleStep / (_NumMinorTicks + 1)
    '    Dim MajorTickValueStep As Single = CSng((_RangeEnd - _RangeStart)) / CSng(_NumMajorTicks)

    '    For i = 1 To _NumMajorTicks
    '        Dim MajorTickAngle As Single = _StartAngle + (i - 1) * MajorTickAngleStep
    '        DrawTickMark(DialCenterPt, MajorTickOuterRadius, MajorTickInnerRadius, MajorTickAngle, _MajorTickThickness, _MajorTickColor, G)
    '        For j = 1 To _NumMinorTicks
    '            Dim MinorTickAngle As Single = MajorTickAngle + MinorTickAngleStep * j
    '            DrawTickMark(DialCenterPt, MinorTickOuterRadius, MinorTickInnerRadius, MinorTickAngle, _MinorTickThickness, _MinorTickColor, G)
    '        Next
    '    Next
    '    DrawTickMark(DialCenterPt, MajorTickOuterRadius, MajorTickInnerRadius, _StartAngle + _Sweep, _MajorTickThickness, _MajorTickColor, G) 'Final tick mark

    '    'Draw Major Labels
    '    If _DisplayMajorLabels Then
    '        If _MajorLabelPosition = MajorLabelPositions.Outside Then
    '            For i = 1 To _NumMajorTicks
    '                Dim MajorTickAngle As Single = _StartAngle + (i - 1) * MajorTickAngleStep
    '                Dim Label As String = Format(_RangeStart + (i - 1) * MajorTickValueStep, _MajorLabelFormat)
    '                'DrawMajorLabel(DialCenterPt, MajorLabelRadius, MajorTickAngle, Label, Me.Font, Me.ForeColor, G)
    '                DrawMajorLabel(DialCenterPt, DialOuterRadius, _MajorLabelsPadding, MajorTickAngle, Label, Me.Font, Me.ForeColor, G)
    '            Next
    '            'DrawMajorLabel(DialCenterPt, MajorLabelRadius, StartAngle + Sweep, Format(RangeEnd, MajorLabelFormat), Me.Font, Me.ForeColor, G) 'Final label
    '            DrawMajorLabel(DialCenterPt, DialOuterRadius, _MajorLabelsPadding, _StartAngle + _Sweep, Format(_RangeEnd, _MajorLabelFormat), Me.Font, Me.ForeColor, G) 'Final label
    '        End If
    '    End If

    '    'Draw Dial Arc
    '    If DialOuterRadius > 0 Then G.DrawArc(New Pen(_AxisColor, _AxisThickness), CircleRect(DialCenterPt, DialOuterRadius), _StartAngle, _Sweep)

    'End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        'Add your custom paint code here
        'Graphics
        Dim G As Graphics = e.Graphics
        G.SmoothingMode = Drawing2D.SmoothingMode.HighQuality


        'Draw Gauge background 
        If _Background.FillStyle = BackgroundType.FillStyles.Gradient Then
            Dim myBrush As LinearGradientBrush
            myBrush = New LinearGradientBrush(Me.ClientRectangle, _Background.BackColor1, _Background.BackColor2, Me._Background.FillGradientStyle)
            G.FillRectangle(myBrush, Me.ClientRectangle)
        Else
            G.FillRectangle(New SolidBrush(_Background.BackColor1), Me.ClientRectangle)
        End If


        'Bounding Rectangle of Control
        Dim ContainerRect As Rectangle = Me.ClientRectangle

        'Pixels needed to accomodate Major Labels
        Dim MajorLabelGap As Single = 0
        Dim TextHeight As Single = 0
        If _MajorLabels.Display AndAlso _MajorLabels.Position = MajorLabelsType.MajorLabelPositions.Outside Then
            TextHeight = G.MeasureString("1234567890", Me.Font).Height
            MajorLabelGap = _MajorLabels.Padding + TextHeight / 2
        Else
            'No gap needed
            MajorLabelGap = 0
            TextHeight = 0
        End If


        'Bounding Rectangle of Dial
        Dim BoundSize As Single
        Dim BoundX As Single
        Dim BoundY As Single
        If MajorLabels.Position = MajorLabelsType.MajorLabelPositions.Outside Then
            BoundSize = Math.Min(ContainerRect.Width, ContainerRect.Height)
            BoundX = ContainerRect.X + (ContainerRect.Width - BoundSize) / 2 + CSng(_AxisThickness) / 2 + 2
            BoundY = ContainerRect.Y + (ContainerRect.Height - BoundSize) / 2 + CSng(_AxisThickness) / 2 + 2
            BoundSize = BoundSize - 2 * CSng(_AxisThickness) - 4
        Else
            BoundSize = Math.Min(ContainerRect.Width, ContainerRect.Height)
            BoundX = ContainerRect.X + (ContainerRect.Width - BoundSize) / 2 + CSng(_AxisThickness) / 2 + 2
            BoundY = ContainerRect.Y + (ContainerRect.Height - BoundSize) / 2 + CSng(_AxisThickness) / 2 + 2
            BoundSize = BoundSize - CSng(_AxisThickness) - 4
        End If
        Dim DialRect As New RectangleF(BoundX, BoundY, BoundSize, BoundSize)

        'Dial Center Pt
        Dim DialCenterPt As New PointF(DialRect.X + DialRect.Width / 2, DialRect.Y + DialRect.Height / 2)

        'Dial Major Label Radius
        Dim MajorLabelRadius As Single = BoundSize / 2 - TextHeight / 2

        'Dial Outer Radius
        Dim DialOuterRadius As Single = MajorLabelRadius - MajorLabelGap

        'Major Tick - Inner/OuterRadii
        Dim MajorTickOuterRadius As Single = DialOuterRadius
        Dim MajorTickInnerRadius As Single = DialOuterRadius - _MajorTicks.TickSize

        'Minor Tick - Inner/Outer Radii
        Dim MinorTickOuterRadius As Single = DialOuterRadius
        Dim MinorTickInnerRadius As Single = DialOuterRadius - _MinorTicks.TickSize

        'Heat Arcs - Inner/Outer Radii
        Dim HeatArcOuterRadius As Single = DialOuterRadius
        Dim HeatArcInnerRadius As Single = HeatArcOuterRadius - Math.Min(Math.Min(_HT1.Width, _HT2.Width), _HT3.Width)


        'Draw Dial Background
        DrawDialBackground(DialCenterPt, DialOuterRadius - _AxisThickness, HeatArcInnerRadius, _StartAngle, _Sweep, _
                           _DialBackground.BackColor1, _DialBackground.BackColor2, _DialBackground.FillStyle, _
                           _DialBackground.FillGradientStyle, _Needle.CenterRadius, _DialBackground.DialStyle, G)


        'Draw Heat Arcs
        Dim StartAngle As Single
        Dim EndAngle As Single
        Dim InnerRadius As Single

        'HT1
        If _HT1.Width > 0 Then
            If _HT1.RangeStart <= _RangeStart Then
                StartAngle = _StartAngle
            Else
                StartAngle = Me.NeedleAngle(_HT1.RangeStart, _RangeStart, _RangeEnd, _StartAngle, _Sweep)
            End If
            If _HT1.RangeEnd >= _RangeEnd Then
                EndAngle = _StartAngle + _Sweep
            Else
                EndAngle = NeedleAngle(_HT1.RangeEnd, _RangeStart, _RangeEnd, _StartAngle, _Sweep)
            End If
            InnerRadius = HeatArcOuterRadius - _HT1.Width
            DrawFilledArcSegment(DialCenterPt, InnerRadius, HeatArcOuterRadius, StartAngle, EndAngle, _HT1.Color, G)
        End If

        'HT2
        If _HT2.Width > 0 Then
            If _HT2.RangeStart <= _RangeStart Then
                StartAngle = _StartAngle
            Else
                StartAngle = Me.NeedleAngle(_HT2.RangeStart, _RangeStart, _RangeEnd, _StartAngle, _Sweep)
            End If
            If _HT2.RangeEnd >= _RangeEnd Then
                EndAngle = _StartAngle + _Sweep
            Else
                EndAngle = NeedleAngle(_HT2.RangeEnd, _RangeStart, _RangeEnd, _StartAngle, _Sweep)
            End If
            InnerRadius = HeatArcOuterRadius - _HT2.Width
            DrawFilledArcSegment(DialCenterPt, InnerRadius, HeatArcOuterRadius, StartAngle, EndAngle, _HT2.Color, G)
        End If

        'HT3
        If _HT3.Width > 0 Then
            If _HT3.RangeStart <= _RangeStart Then
                StartAngle = _StartAngle
            Else
                StartAngle = Me.NeedleAngle(_HT3.RangeStart, _RangeStart, _RangeEnd, _StartAngle, _Sweep)
            End If
            If _HT3.RangeEnd >= _RangeEnd Then
                EndAngle = _StartAngle + _Sweep
            Else
                EndAngle = NeedleAngle(_HT3.RangeEnd, _RangeStart, _RangeEnd, _StartAngle, _Sweep)
            End If
            InnerRadius = HeatArcOuterRadius - _HT3.Width
            DrawFilledArcSegment(DialCenterPt, InnerRadius, HeatArcOuterRadius, StartAngle, EndAngle, _HT3.Color, G)
        End If


        'Draw Major/Minor Tick Marks
        Dim MajorTickAngleStep As Single = _Sweep / _MajorTicks.NumTicks
        Dim MinorTickAngleStep As Single = MajorTickAngleStep / (_MinorTicks.NumTicks + 1)
        Dim MajorTickValueStep As Single = CSng((_RangeEnd - _RangeStart)) / CSng(_MajorTicks.NumTicks)

        For i = 1 To _MajorTicks.NumTicks
            Dim MajorTickAngle As Single = _StartAngle + (i - 1) * MajorTickAngleStep
            DrawTickMark(DialCenterPt, MajorTickOuterRadius, MajorTickInnerRadius, MajorTickAngle, _MajorTicks.TickThickness, _MajorTicks.TickColor, G)
            For j = 1 To _MinorTicks.NumTicks
                Dim MinorTickAngle As Single = MajorTickAngle + MinorTickAngleStep * j
                DrawTickMark(DialCenterPt, MinorTickOuterRadius, MinorTickInnerRadius, MinorTickAngle, _MinorTicks.TickThickness, _MinorTicks.TickColor, G)
            Next
        Next
        DrawTickMark(DialCenterPt, MajorTickOuterRadius, MajorTickInnerRadius, _StartAngle + _Sweep, _MajorTicks.TickThickness, _MajorTicks.TickColor, G) 'Final tick mark

        'Draw Major Labels
        If _MajorLabels.Display Then
            Dim AdjustmentOuter As Single = 10
            If _MajorLabels.Position = MajorLabelsType.MajorLabelPositions.Outside Then
                For i = 1 To _MajorTicks.NumTicks
                    Dim MajorTickAngle As Single = _StartAngle + (i - 1) * MajorTickAngleStep
                    Dim Label As String = Format(_RangeStart + (i - 1) * MajorTickValueStep, _MajorLabels.Format)
                    'DrawMajorLabel(DialCenterPt, MajorLabelRadius, MajorTickAngle, Label, Me.Font, Me.ForeColor, G)
                    DrawMajorLabel(DialCenterPt, DialOuterRadius + AdjustmentOuter, _MajorLabels.Padding, MajorTickAngle, Label, Me.Font, Me.ForeColor, G)
                Next
                'DrawMajorLabel(DialCenterPt, MajorLabelRadius, StartAngle + Sweep, Format(RangeEnd, MajorLabelFormat), Me.Font, Me.ForeColor, G) 'Final label
                DrawMajorLabel(DialCenterPt, DialOuterRadius + AdjustmentOuter, _MajorLabels.Padding, _StartAngle + _Sweep, Format(_RangeEnd, _MajorLabels.Format), Me.Font, Me.ForeColor, G) 'Final label
            Else
                'Labels positioned "inside"
                'Dim Adjustment As Single = G.MeasureString("1234567890", Me.Font).Height + _MajorLabels.Padding
                Dim AdjustmentInner As Single = G.MeasureString("1234567890", Me.Font).Height + _MajorLabels.Padding
                For i = 1 To _MajorTicks.NumTicks
                    Dim MajorTickAngle As Single = _StartAngle + (i - 1) * MajorTickAngleStep
                    Dim Label As String = Format(_RangeStart + (i - 1) * MajorTickValueStep, _MajorLabels.Format)
                    'DrawMajorLabel(DialCenterPt, MajorLabelRadius, MajorTickAngle, Label, Me.Font, Me.ForeColor, G)
                    DrawMajorLabel(DialCenterPt, DialOuterRadius - AdjustmentInner, 0, MajorTickAngle, Label, Me.Font, Me.ForeColor, G)
                Next
                'DrawMajorLabel(DialCenterPt, MajorLabelRadius, StartAngle + Sweep, Format(RangeEnd, MajorLabelFormat), Me.Font, Me.ForeColor, G) 'Final label
                DrawMajorLabel(DialCenterPt, DialOuterRadius - AdjustmentInner, 0, _StartAngle + _Sweep, Format(_RangeEnd, _MajorLabels.Format), Me.Font, Me.ForeColor, G) 'Final label
            End If
        End If

        'Draw Dial Arc
        If DialOuterRadius > 0 Then G.DrawArc(New Pen(_AxisColor, _AxisThickness), CircleRect(DialCenterPt, DialOuterRadius), _StartAngle, _Sweep)


        'Draw Needle
        Dim NeedleRadius As Single = _Needle.PercentageLength * DialOuterRadius / 100
        DrawNeedle(DialCenterPt, NeedleRadius, NeedleAngle(_GaugeValue, _RangeStart, _RangeEnd, _StartAngle, _Sweep), _Needle.Color, _Needle.Thickness, _Needle.CenterRadius, _Needle.CenterColor, G)

        'Draw Highlights
        'DrawDialHighlight(DialCenterPt, HeatArcInnerRadius, G)
    End Sub

#End Region

#Region "Event Handlers"
    Private Sub _Background_PropertyChanged(ByVal PropertyName As String) Handles _Background.PropertyChanged
        Me.Invalidate()
    End Sub
    Private Sub _DialBackground_PropertyChanged(ByVal PropertyName As String) Handles _DialBackground.PropertyChanged
        Me.Invalidate()
    End Sub
    Private Sub _HT_PropertyChanged(ByVal PropertyName As String) Handles _HT1.PropertyChanged, _HT2.PropertyChanged, _HT3.PropertyChanged
        Me.Invalidate()
    End Sub
    Private Sub _MajorLabels_PropertyChanged(ByVal PropertyName As String) Handles _MajorLabels.PropertyChanged
        Me.Invalidate()
    End Sub
    Private Sub _MajorTicks_PropertyChanged(ByVal PropertyName As String) Handles _MajorTicks.PropertyChanged
        Me.Invalidate()
    End Sub
    Private Sub _MinorTicks_PropertyChanged(ByVal PropertyName As String) Handles _MinorTicks.PropertyChanged
        Me.Invalidate()
    End Sub
    Private Sub _Needle_PropertyChanged(ByVal PropertyName As String) Handles _Needle.PropertyChanged
        Me.Invalidate()
    End Sub
#End Region

#Region "Transparency Support"
    Private Const WS_EX_TRANSPARENT As Int16 = &H20

    Friend Sub SetTransparencyMode(ByVal IsOn As Boolean)
        If IsOn Then
            'Support transparency - turn off double-buffering
            Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, False) 'Turn double-buffering off for transparency
            Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
            Me.SetStyle(ControlStyles.Opaque, True)
        Else
            'No transparency support - enable double-buffering
            Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True) 'Turn double-buffering off for transparency
            Me.SetStyle(ControlStyles.SupportsTransparentBackColor, False)
            Me.SetStyle(ControlStyles.Opaque, False)
        End If
        If Me.Parent Is Nothing Then
            Me.Refresh()
        Else
            Me.Parent.Refresh()
        End If
    End Sub
    Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
        Get
            Dim cp As CreateParams = MyBase.CreateParams
            cp.ExStyle = cp.ExStyle Or WS_EX_TRANSPARENT
            Return cp
        End Get
    End Property
#End Region

#Region "Drawing Helper Routines"
    Private Sub DrawTickMark(ByVal CenterPt As PointF, ByVal Radius1 As Single, ByVal Radius2 As Single, ByVal AngleDeg As Single, ByVal TickThickness As Integer, ByVal TickColor As Color, ByRef G As Graphics)
        If Radius1 > 0 AndAlso Radius2 > 0 Then
            Dim pt1 As PointF = PtOnCirc(CenterPt, Radius1, AngleDeg)
            Dim pt2 As PointF = PtOnCirc(CenterPt, Radius2, AngleDeg)

            G.DrawLine(New Pen(TickColor, TickThickness), pt1, pt2)
        End If
    End Sub
    Private Sub DrawMajorLabel(ByVal CenterPt As PointF, ByVal Radius As Single, ByVal Padding As Single, ByVal AngleDeg As Single, ByVal Text As String, ByVal TextFont As Font, ByVal TextColor As Color, ByRef G As Graphics)
        If Radius + Padding > 0 Then
            Dim pt1 As PointF = PtOnCirc(CenterPt, Radius + Padding, AngleDeg)

            Dim format As New StringFormat()
            format.Alignment = StringAlignment.Center
            format.LineAlignment = StringAlignment.Center

            G.DrawString(Text, TextFont, New SolidBrush(TextColor), pt1, format)
        End If
    End Sub
    Private Sub DrawFilledArcSegment(ByVal CenterPt As PointF, ByVal Radius1 As Single, ByVal Radius2 As Single, ByVal StartAngle As Single, ByVal EndAngle As Single, ByVal Color As Color, ByVal G As Graphics)
        Dim Path As New System.Drawing.Drawing2D.GraphicsPath

        If Radius1 > 0 And Radius2 > 0 Then
            Path.AddLine(PtOnCirc(CenterPt, Radius1, StartAngle), PtOnCirc(CenterPt, Radius2, StartAngle))
            Path.AddArc(New RectangleF(CenterPt.X - Radius2, CenterPt.Y - Radius2, Radius2 * 2, Radius2 * 2), StartAngle, EndAngle - StartAngle)
            Path.AddLine(PtOnCirc(CenterPt, Radius2, EndAngle), PtOnCirc(CenterPt, Radius1, EndAngle))
            Path.AddArc(New RectangleF(CenterPt.X - Radius1, CenterPt.Y - Radius1, Radius1 * 2, Radius1 * 2), StartAngle, EndAngle - StartAngle)


            Path.CloseFigure()

            'Dim myBrush As New SolidBrush(Color.FromArgb(100, Color.R, Color.G, Color.B))
            Dim myBrush As New SolidBrush(Color)

            G.FillPath(myBrush, Path)
        End If
    End Sub
    Private Sub DrawNeedle(ByVal CenterPt As PointF, ByVal Radius As Single, ByVal AngleDeg As Single, ByVal Color As Color, ByVal Thickness As Single, ByVal NeedleCenterRadius As Single, ByVal NeedleCenterColor As Color, ByRef G As Graphics)
        Dim Pt1 As PointF
        Dim Pt2 As PointF
        Dim Pt3 As PointF

        If Radius > 0 AndAlso Thickness > 0 Then
            Pt1 = PtOnCirc(CenterPt, Thickness / 2, AngleDeg + 90)
            Pt2 = PtOnCirc(CenterPt, Thickness / 2, AngleDeg - 90)
            Pt3 = PtOnCirc(CenterPt, Radius, AngleDeg)


            Dim ColorLighter As Color = Color.FromArgb(Math.Min(Color.R + 150, 255), Math.Min(Color.G + 150, 255), Math.Min(Color.B + 150, 255))
            Dim ColorDarker As Color = Color.FromArgb(Math.Max(Color.R - 150, 0), Math.Max(Color.G - 150, 0), Math.Max(Color.B - 150, 0))
            Dim FillBrush1 As New LinearGradientBrush(Pt1, Pt2, ColorLighter, Color)
            Dim FillBrush2 As New LinearGradientBrush(Pt2, CenterPt, Color.White, ColorLighter)

            'Needle
            G.FillPolygon(FillBrush1, New PointF() {Pt1, Pt2, Pt3})

            'Needle Center
            Dim NeedleCenterColorLighter As Color = Color.FromArgb(Math.Min(NeedleCenterColor.R + 150, 255), Math.Min(NeedleCenterColor.G + 150, 255), Math.Min(NeedleCenterColor.B + 150, 255))
            Dim DialCenterBrush As New LinearGradientBrush(CircleRect(CenterPt, NeedleCenterRadius), NeedleCenterColorLighter, NeedleCenterColor, LinearGradientMode.ForwardDiagonal)
            G.FillEllipse(DialCenterBrush, CircleRect(CenterPt, NeedleCenterRadius))
        End If
    End Sub
    Private Sub DrawDialBackground(ByVal CenterPt As PointF, ByVal OuterRadius As Single, ByVal InnerRadius As Single, ByVal StartAngle As Single, ByVal Sweep As Single, ByVal Color1 As Color, ByVal Color2 As Color, ByVal FillStyle As DialBackgroundType.FillStyles, ByVal GradientMode As LinearGradientMode, ByVal NeedleCenterRadius As Single, ByVal DialFillMode As DialBackgroundType.DialFillModes, ByRef G As Graphics)
        If OuterRadius > 0 AndAlso InnerRadius > 0 AndAlso NeedleCenterRadius > 0 Then
            If DialFillMode = DialBackgroundType.DialFillModes.Extruded Then
                Dim CircRect As RectangleF = CircleRect(CenterPt, InnerRadius)

                'Dim ModInnerRadius As Single = NeedleCenterRadius + (InnerRadius - NeedleCenterRadius) / 2
                Dim ModInnerRadius As Single = NeedleCenterRadius + (InnerRadius - NeedleCenterRadius) * Me.DialBackground.ExtrusionPercentage / 100


                Dim Pt1 As PointF = PtOnCirc(CenterPt, InnerRadius, StartAngle)
                Dim Pt2 As PointF = PtOnCirc(CenterPt, ModInnerRadius, StartAngle)
                Dim Pt3 As PointF = PtOnCirc(CenterPt, ModInnerRadius, StartAngle + Sweep)
                Dim Pt4 As PointF = PtOnCirc(CenterPt, InnerRadius, StartAngle + Sweep)

                Dim Path As New GraphicsPath
                Path.AddArc(CircRect, StartAngle, Sweep)
                Path.AddLine(Pt4, Pt3)
                'Path.AddLine(Pt3, Pt2)
                Path.AddArc(CircleRect(CenterPt, ModInnerRadius), StartAngle + Sweep, 360 - Sweep)
                Path.AddLine(Pt2, Pt1)

                If FillStyle = DialBackgroundType.FillStyles.Solid Then
                    If Color1 <> Color.Transparent Then
                        Dim FillBrush As New SolidBrush(Color1)
                        'G.FillEllipse(FillBrush, CircRect)
                        G.FillPath(FillBrush, Path)
                    End If
                Else
                    Dim FillBrush As New LinearGradientBrush(CircRect, Color1, Color2, GradientMode)
                    'G.FillEllipse(FillBrush, CircRect)
                    G.FillPath(FillBrush, Path)
                End If
            Else
                Dim CircRect As RectangleF = CircleRect(CenterPt, OuterRadius)

                If FillStyle = DialBackgroundType.FillStyles.Solid Then
                    If Color1 <> Color.Transparent Then
                        Dim FillBrush As New SolidBrush(Color1)
                        G.FillEllipse(FillBrush, CircRect)
                    End If
                Else
                    Dim FillBrush As New LinearGradientBrush(CircRect, Color1, Color2, GradientMode)
                    G.FillEllipse(FillBrush, CircRect)
                End If
            End If
        End If
    End Sub
    Private Sub DrawDialHighlight(ByVal CenterPt As PointF, ByVal DialRadius As Single, ByRef G As Graphics)
        Dim DialRect As RectangleF = CircleRect(CenterPt, DialRadius)
        Dim HighlightRect As RectangleF
        HighlightRect.X = DialRect.X + 10
        HighlightRect.Y = DialRect.Y
        HighlightRect.Width = DialRect.Width - 20
        HighlightRect.Height = DialRect.Height * 3 / 4

        Dim Color1 As Color = Color.FromArgb(15, 255, 255, 255)
        Dim Color2 As Color = Color.FromArgb(60, 255, 255, 255)

        Dim Brush As New LinearGradientBrush(HighlightRect, Color1, Color2, LinearGradientMode.Vertical)
        G.FillEllipse(Brush, HighlightRect)
    End Sub
#End Region

#Region "Private Helper Routines"
    Private Function NeedleAngle(ByVal Value As Double, ByVal RangeStart As Double, ByVal RangeEnd As Double, ByVal StartAngle As Single, ByVal Sweep As Single) As Single
        Dim NormalizedValue As Double = CDbl(Value)
        If NormalizedValue < RangeStart Then NormalizedValue = RangeStart
        If NormalizedValue > RangeEnd Then NormalizedValue = RangeEnd

        Dim ratio As Double = (NormalizedValue - RangeStart) / (RangeEnd - RangeStart)
        Dim NeedleAngleDeg As Single = StartAngle + Sweep * CSng(ratio)
        Return NeedleAngleDeg
    End Function
    Private Function CircleRect(ByVal CenterPt As PointF, ByVal Radius As Single) As RectangleF
        Return New RectangleF(CenterPt.X - Radius, CenterPt.Y - Radius, Radius * 2, Radius * 2)
    End Function
    Private Function PtOnCirc(ByVal CenterPt As PointF, ByVal Radius As Single, ByVal AngleDeg As Single) As PointF
        Dim AngleRad As Double = CDbl(AngleDeg) * Math.PI / CDbl(180)


        Dim X As Single = CenterPt.X + Radius * CSng(Math.Cos(AngleRad))
        Dim Y As Single = CenterPt.Y + Radius * CSng(Math.Sin(AngleRad))

        Return New PointF(X, Y)
    End Function
    Private Function CosDeg(ByVal AngleDeg As Single) As Single
        Return CSng(Math.Cos(Math.PI * AngleDeg / 180.0!))
    End Function
    Private Function SinDeg(ByVal AngleDeg As Single) As Single
        Return CSng(Math.Sin(Math.PI * AngleDeg / 180.0!))
    End Function
#End Region

#Region "Background Type"
    Public Class BackgroundType
        'Defaults
        Private Const def_SupportTransparency As Boolean = False

        Private def_BackColor1 As Color = Color.SteelBlue
        Private def_BackColor2 As Color = Color.LightSteelBlue
        Private def_FillStyle As FillStyles = FillStyles.Gradient
        Private def_FillGradientStyle As LinearGradientMode = LinearGradientMode.Vertical


        'Private Properties
        Private _SupportTransparency As Boolean = def_SupportTransparency

        Private _BackColor1 As Color = def_BackColor1
        Private _BackColor2 As Color = def_BackColor2
        Private _FillStyle As FillStyles = def_FillStyle
        Private _GradientOrientation As LinearGradientMode = def_FillGradientStyle

        Private _ParentCtl As RadialGauge = Nothing


        'Enumerations
        Public Enum FillStyles As Integer
            Solid = 0
            Gradient = 1
        End Enum

        'Public Events
        Public Event PropertyChanged(ByVal PropertyName As String)

        'Public Interface
        Friend Sub New(ByVal Control As RadialGauge)
            _ParentCtl = Control
        End Sub


        <Description("The background color of the control. Primary color if FillStyle is set to Solid or gradient start color if FillStyle is set to Gradient."), _
            BrowsableAttribute(True)> _
        Public Property BackColor1() As Color
            Get
                Return _BackColor1
            End Get
            Set(ByVal value As Color)
                _BackColor1 = value
                If _BackColor1 = Color.Transparent AndAlso _FillStyle = FillStyles.Solid Then
                    _ParentCtl.SetTransparencyMode(True)
                Else
                    _ParentCtl.SetTransparencyMode(False)
                End If
                RaiseEvent PropertyChanged("BackColor1")
            End Set
        End Property

        Public Sub ResetBackColor1()
            BackColor1 = def_BackColor1
        End Sub

        Public Function ShouldSerializeBackColor1() As Boolean
            Return Not (BackColor1.Equals(def_BackColor1))
        End Function

        <Description("The secondary color of the control background when FillStyle is set to Gradient."), _
            BrowsableAttribute(True)> _
        Public Property BackColor2() As Color
            Get
                Return _BackColor2
            End Get
            Set(ByVal value As Color)
                _BackColor2 = value
                RaiseEvent PropertyChanged("BackColor2")
            End Set
        End Property
        Public Sub ResetBackColor2()
            BackColor2 = def_BackColor2
        End Sub
        Public Function ShouldSerializeBackColor2() As Boolean
            Return Not (BackColor2.Equals(def_BackColor2))
        End Function

        <Description("The FillStyle for the Background of this control."), _
                BrowsableAttribute(True)> _
        Public Property FillStyle() As FillStyles
            Get
                Return _FillStyle
            End Get
            Set(ByVal value As FillStyles)
                _FillStyle = value
                If _FillStyle = FillStyles.Solid AndAlso _BackColor1 = Color.Transparent Then
                    _ParentCtl.SetTransparencyMode(True)
                Else
                    _ParentCtl.SetTransparencyMode(False)
                End If
                RaiseEvent PropertyChanged("FillStyle")
            End Set
        End Property
        Public Sub ResetFillStyle()
            FillStyle = def_FillStyle
        End Sub
        Public Function ShouldSerializeFillStyle() As Boolean
            Return Not (FillStyle.Equals(def_FillStyle))
        End Function

        <Description("The gradient style of the control background when FillStyle is set to Gradient."), _
            BrowsableAttribute(True)> _
        Public Property FillGradientStyle() As LinearGradientMode
            Get
                Return _GradientOrientation
            End Get
            Set(ByVal value As LinearGradientMode)
                _GradientOrientation = value
                RaiseEvent PropertyChanged("FillGradientStyle")
            End Set
        End Property
        Public Sub ResetFillGradientStyle()
            FillGradientStyle = def_FillGradientStyle
        End Sub
        Public Function ShouldSerializeFillGradientStyle() As Boolean
            Return Not (FillGradientStyle.Equals(def_FillGradientStyle))
        End Function

        Public Sub Reset()
            _BackColor1 = def_BackColor1
            _BackColor2 = def_BackColor2
            _FillStyle = def_FillStyle
            _GradientOrientation = def_FillGradientStyle

            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If _BackColor1.Equals(def_BackColor1) _
                    AndAlso _BackColor2.Equals(def_BackColor2) _
                    AndAlso _FillStyle.Equals(def_FillStyle) _
                    AndAlso _GradientOrientation.Equals(def_FillGradientStyle) Then
                Return False
            Else
                Return True
            End If
        End Function

        Public Overrides Function ToString() As String
            Return "(Background)"
        End Function
    End Class
    Public Class BackgroundTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(BackgroundType))
        End Function
    End Class
#End Region

#Region "Dial Background Type"
    Public Class DialBackgroundType
        'Defaults
        Private def_BackColor1 As Color = Color.Red
        Private def_BackColor2 As Color = Color.Yellow
        Private def_FillStyle As FillStyles = FillStyles.Gradient
        Private def_FillGradientStyle As LinearGradientMode = LinearGradientMode.BackwardDiagonal
        Private def_DialFillMode As DialFillModes = DialFillModes.Extruded
        Private def_ExtrusionPercentage As Single = 30

        'Private Properties
        Private _BackColor1 As Color = def_BackColor1
        Private _BackColor2 As Color = def_BackColor2
        Private _FillStyle As FillStyles = def_FillStyle
        Private _GradientOrientation As LinearGradientMode = def_FillGradientStyle
        Private _DialFillMode As DialFillModes = def_DialFillMode
        Private _ExtrusionPercentage As Single = def_ExtrusionPercentage

        'Enumerations
        Public Enum FillStyles As Integer
            Solid = 0
            Gradient = 1
        End Enum
        Public Enum DialFillModes As Integer
            Complete = 0
            Extruded = 1
        End Enum

        'Public Events
        Public Event PropertyChanged(ByVal PropertyName As String)

        'Public Interface
        Friend Sub New()

        End Sub


        <Description("The background color of the Dial. Primary color if FillStyle is set to Solid or gradient start color if FillStyle is set to Gradient."), _
            BrowsableAttribute(True)> _
        Public Property BackColor1() As Color
            Get
                Return _BackColor1
            End Get
            Set(ByVal value As Color)
                _BackColor1 = value
                RaiseEvent PropertyChanged("DialBackColor1")
            End Set
        End Property

        Public Sub ResetBackColor1()
            BackColor1 = def_BackColor1
        End Sub

        Public Function ShouldSerializeBackColor1() As Boolean
            Return Not (BackColor1.Equals(def_BackColor1))
        End Function

        <Description("The secondary color of the Dial background when FillStyle is set to Gradient."), _
            BrowsableAttribute(True)> _
        Public Property BackColor2() As Color
            Get
                Return _BackColor2
            End Get
            Set(ByVal value As Color)
                _BackColor2 = value
                RaiseEvent PropertyChanged("DialBackColor2")
            End Set
        End Property
        Public Sub ResetBackColor2()
            BackColor2 = def_BackColor2
        End Sub
        Public Function ShouldSerializeBackColor2() As Boolean
            Return Not (BackColor2.Equals(def_BackColor2))
        End Function

        <Description("The FillStyle for the Background of the Dial."), _
                BrowsableAttribute(True)> _
        Public Property FillStyle() As FillStyles
            Get
                Return _FillStyle
            End Get
            Set(ByVal value As FillStyles)
                _FillStyle = value
                RaiseEvent PropertyChanged("DialFillStyle")
            End Set
        End Property
        Public Sub ResetFillStyle()
            FillStyle = def_FillStyle
        End Sub
        Public Function ShouldSerializeFillStyle() As Boolean
            Return Not (FillStyle.Equals(def_FillStyle))
        End Function

        <Description("The gradient style of the Dial background when FillStyle is set to Gradient."), _
            BrowsableAttribute(True)> _
        Public Property FillGradientStyle() As LinearGradientMode
            Get
                Return _GradientOrientation
            End Get
            Set(ByVal value As LinearGradientMode)
                _GradientOrientation = value
                RaiseEvent PropertyChanged("DialFillGradientStyle")
            End Set
        End Property
        Public Sub ResetFillGradientStyle()
            FillGradientStyle = def_FillGradientStyle
        End Sub
        Public Function ShouldSerializeFillGradientStyle() As Boolean
            Return Not (FillGradientStyle.Equals(def_FillGradientStyle))
        End Function

        <Description("The Dial extrusion style."), _
            BrowsableAttribute(True)> _
        Public Property DialStyle() As DialFillModes
            Get
                Return _DialFillMode
            End Get
            Set(ByVal value As DialFillModes)
                _DialFillMode = value
                RaiseEvent PropertyChanged("DialStyle")
            End Set
        End Property
        Public Sub ResetDialStyle()
            DialStyle = def_DialFillMode
        End Sub
        Public Function ShouldSerializeDialStyle() As Boolean
            Return Not (DialStyle.Equals(def_DialFillMode))
        End Function

        <Description("Defines the relative size of the extruded gauge center when gauge is set to Extruded mode.")> _
       Public Property ExtrusionPercentage() As Single
            Get
                Return _ExtrusionPercentage
            End Get
            Set(ByVal value As Single)
                If value < 0 Then value = 0
                _ExtrusionPercentage = value
                RaiseEvent PropertyChanged("ExtrusionPercentage")
            End Set
        End Property
        Public Sub ResetExtrusionPercentage()
            Me.ExtrusionPercentage = def_ExtrusionPercentage
        End Sub
        Public Function ShouldSerializeExtrusionPercentage() As Boolean
            Return Not (ExtrusionPercentage.Equals(def_ExtrusionPercentage))
        End Function

        Public Sub Reset()
            _BackColor1 = def_BackColor1
            _BackColor2 = def_BackColor2
            _FillStyle = def_FillStyle
            _GradientOrientation = def_FillGradientStyle
            _DialFillMode = def_DialFillMode

            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If _BackColor1.Equals(def_BackColor1) _
                    AndAlso _BackColor2.Equals(def_BackColor2) _
                    AndAlso _FillStyle.Equals(def_FillStyle) _
                    AndAlso _GradientOrientation.Equals(def_FillGradientStyle) _
                    AndAlso _DialFillMode.Equals(def_DialFillMode) Then
                Return False
            Else
                Return True
            End If
        End Function

        Public Overrides Function ToString() As String
            Return "(DialBackground)"
        End Function
    End Class

    Public Class DialBackgroundTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(DialBackgroundType))
        End Function
    End Class
#End Region

#Region "HeatArc"
    Public Class HeatArc
        Private def_Width As Single = 20
        Private def_RangeStart As Double = 0
        Private def_RangeEnd As Double = 20
        Private def_Color As Color = Color.Blue


        Private _Width As Single = def_Width
        Private _RangeStart As Double = def_RangeStart
        Private _RangeEnd As Double = def_RangeEnd
        Private _Color As Color = def_Color



        'Public Events
        Public Event PropertyChanged(ByVal PropertyName As String)

        'Public Interface
        Friend Sub New(ByVal DefWidth As Single, ByVal DefRangeStart As Double, ByVal DefRangeEnd As Double, ByVal DefColor As Color)
            def_Width = DefWidth
            def_RangeStart = DefRangeStart
            def_RangeEnd = DefRangeEnd
            def_Color = DefColor

            _Width = def_Width
            _RangeStart = def_RangeStart
            _RangeEnd = def_RangeEnd
            _Color = def_Color
        End Sub

        <Description("The width of the heat arc."), _
                    BrowsableAttribute(True)> _
        Public Property Width() As Single
            Get
                Return _Width
            End Get
            Set(ByVal value As Single)
                _Width = value
                RaiseEvent PropertyChanged("Width")
            End Set
        End Property
        Public Sub ResetWidth()
            Me.Width = def_Width
        End Sub
        Public Function ShouldSerializeWidth() As Boolean
            Return Not (Width.Equals(def_Width))
        End Function


        <Description("The start value of the heat arc."), _
                    BrowsableAttribute(True)> _
        Public Property RangeStart() As Double
            Get
                Return _RangeStart
            End Get
            Set(ByVal value As Double)
                _RangeStart = value
                RaiseEvent PropertyChanged("RangeStart")
            End Set
        End Property
        Public Sub ResetRangeStart()
            Me.RangeStart = def_RangeStart
        End Sub
        Public Function ShouldSerializeRangeStart() As Boolean
            Return Not (RangeStart.Equals(def_RangeStart))
        End Function


        <Description("The end value of the heat arc."), _
                    BrowsableAttribute(True)> _
        Public Property RangeEnd() As Double
            Get
                Return _RangeEnd
            End Get
            Set(ByVal value As Double)
                _RangeEnd = value
                RaiseEvent PropertyChanged("RangeEnd")
            End Set
        End Property
        Public Sub ResetRangeEnd()
            Me.RangeEnd = def_RangeEnd
        End Sub
        Public Function ShouldSerializeRangeEnd() As Boolean
            Return Not (RangeEnd.Equals(def_RangeEnd))
        End Function


        <Description("The color of the heat arc."), _
                    BrowsableAttribute(True)> _
        Public Property Color() As Color
            Get
                Return _Color
            End Get
            Set(ByVal value As Color)
                _Color = value
                RaiseEvent PropertyChanged("Color")
            End Set
        End Property
        Public Sub ResetColor()
            Me.Color = def_Color
        End Sub
        Public Function ShouldSerializeColor() As Boolean
            Return Not (Color.Equals(def_Color))
        End Function



        Public Sub Reset()
            _Width = def_Width
            _RangeStart = def_RangeStart
            _RangeEnd = def_RangeEnd
            _Color = def_Color

            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If _Width.Equals(def_Width) _
                    AndAlso _RangeStart.Equals(def_RangeStart) _
                    AndAlso _RangeEnd.Equals(def_RangeEnd) _
                    AndAlso _Color.Equals(def_Color) Then
                Return False
            Else
                Return True
            End If
        End Function

        Public Overrides Function ToString() As String
            Return "(Heat Arc)"
        End Function

    End Class
    Public Class HeatArcTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(HeatArc))
        End Function
    End Class
#End Region

#Region "MajorLabelsType"
    Public Class MajorLabelsType
        Private def_Display As Boolean = True
        Private def_Padding As Integer = 3
        Private def_Position As MajorLabelPositions = MajorLabelPositions.Outside
        Private def_Format As String = "#,##0.#"

        Private _Display As Boolean = def_Display
        Private _Padding As Integer = def_Padding
        Private _Position As MajorLabelPositions = def_Position
        Private _Format As String = def_Format

        Public Enum MajorLabelPositions As Integer
            Outside = 0
            Inside = 1
        End Enum

        'Public Events
        Public Event PropertyChanged(ByVal PropertyName As String)


        <Description("Determines whether Value labels should be displayed for the Major Ticks."), Browsable(True)> _
        Public Property Display() As Boolean
            Get
                Return _Display
            End Get
            Set(ByVal value As Boolean)
                _Display = value
                RaiseEvent PropertyChanged("Display")
            End Set
        End Property
        Public Sub ResetDisplay()
            Me.Display = def_Display
        End Sub
        Public Function ShouldSerializeDisplay() As Boolean
            Return Not (Display.Equals(def_Display))
        End Function


        <Description("The padding between the major tick labels and the edge of the dial."), Browsable(True)> _
        Public Property Padding() As Integer
            Get
                Return _Padding
            End Get
            Set(ByVal value As Integer)
                _Padding = value
                RaiseEvent PropertyChanged("Padding")
            End Set
        End Property
        Public Sub ResetPadding()
            Me.Padding = def_Padding
        End Sub
        Public Function ShouldSerializePadding() As Boolean
            Return Not (Padding.Equals(def_Padding))
        End Function


        <Description("Determines whether Major Tick labels should be displayed inside or outside the dial."), Browsable(True)> _
        Public Property Position() As MajorLabelPositions
            Get
                Return _Position
            End Get
            Set(ByVal value As MajorLabelPositions)
                _Position = value
                RaiseEvent PropertyChanged("Position")
            End Set
        End Property
        Public Sub ResetPosition()
            Me.Position = def_Position
        End Sub
        Public Function ShouldSerializePosition() As Boolean
            Return Not (Position.Equals(def_Position))
        End Function


        <Description("Defines the numerical formatting for the Major Tick label display. Uses standard .NET custom string formatting rules."), Browsable(True)> _
        Public Property Format() As String
            Get
                Return _Format
            End Get
            Set(ByVal value As String)
                _Format = value
                RaiseEvent PropertyChanged("Format")
            End Set
        End Property
        Public Sub ResetFormat()
            Me.Format = def_Format
        End Sub
        Public Function ShouldSerializeFormat() As Boolean
            Return Not (Format.Equals(def_Format))
        End Function

        Public Sub Reset()
            _Display = def_Display
            _Padding = def_Padding
            _Position = def_Position
            _Format = def_Format

            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If _Display.Equals(def_Display) _
                    AndAlso _Padding.Equals(def_Padding) _
                    AndAlso _Position.Equals(def_Position) _
                    AndAlso _Format.Equals(def_Format) Then
                Return False
            Else
                Return True
            End If
        End Function

        Public Overrides Function ToString() As String
            Return "(Major Labels Format)"
        End Function
    End Class
    Public Class MajorLabelsTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(MajorLabelsType))
        End Function
    End Class
#End Region

#Region "MajorTicksType"
    Public Class MajorTicksType
        Private def_NumTicks As Integer = 10
        Private def_TickSize As Single = 10
        Private def_TickThickness As Integer = 3
        Private def_TickColor As Color = Color.Black

        Private _NumTicks As Integer = def_NumTicks
        Private _TickSize As Single = def_TickSize
        Private _TickThickness As Integer = def_TickThickness
        Private _TickColor As Color = def_TickColor

        'Public Events
        Public Event PropertyChanged(ByVal PropertyName As String)


        Public Sub New()

        End Sub


        <Description("The number of major ticks on the dial scale. Set to 0 for no tick marks.")> _
        Public Property NumTicks() As Integer
            Get
                Return _NumTicks
            End Get
            Set(ByVal value As Integer)
                If value < 0 Then value = 0
                _NumTicks = value
                RaiseEvent PropertyChanged("NumTicks")
            End Set
        End Property
        Public Sub ResetNumTicks()
            Me.NumTicks = def_NumTicks
        End Sub
        Public Function ShouldSerializeNumTicks() As Boolean
            Return Not (NumTicks.Equals(def_NumTicks))
        End Function

        <Description("Determines the size of the lines used for the Major Ticks.")> _
        Public Property TickSize() As Single
            Get
                Return _TickSize
            End Get
            Set(ByVal value As Single)
                If value < 0 Then value = 0
                _TickSize = value
                RaiseEvent PropertyChanged("TickSize")
            End Set
        End Property
        Public Sub ResetTickSize()
            Me.TickSize = def_TickSize
        End Sub
        Public Function ShouldSerializeTickSize() As Boolean
            Return Not (TickSize.Equals(def_TickSize))
        End Function

        <Description("The thickness of the lines used for the Major Ticks. Set to 0 to hide tick marks.")> _
        Public Property TickThickness() As Integer
            Get
                Return _TickThickness
            End Get
            Set(ByVal value As Integer)
                If value < 0 Then value = 0
                _TickThickness = value
                RaiseEvent PropertyChanged("TickThickness")
            End Set
        End Property
        Public Sub ResetTickThickness()
            Me.TickThickness = def_TickThickness
        End Sub
        Public Function ShouldSerializeTickThickness() As Boolean
            Return Not (TickThickness.Equals(def_TickThickness))
        End Function

        <Description("The color of the lines used for the Major Ticks.")> _
        Public Property TickColor() As Color
            Get
                Return _TickColor
            End Get
            Set(ByVal value As Color)
                _TickColor = value
                RaiseEvent PropertyChanged("TickColor")
            End Set
        End Property
        Public Sub ResetTickColor()
            Me.TickColor = def_TickColor
        End Sub
        Public Function ShouldSerializeTickColor() As Boolean
            Return Not (TickColor.Equals(def_TickColor))
        End Function


        Public Sub Reset()
            _NumTicks = def_NumTicks
            _TickSize = def_TickSize
            _TickThickness = def_TickThickness
            _TickColor = def_TickColor

            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If _NumTicks.Equals(def_NumTicks) _
                    AndAlso _TickSize.Equals(def_TickSize) _
                    AndAlso _TickThickness.Equals(def_TickThickness) _
                    AndAlso _TickColor.Equals(def_TickColor) Then
                Return False
            Else
                Return True
            End If
        End Function

        Public Overrides Function ToString() As String
            Return "(Major Ticks Format)"
        End Function
    End Class
    Public Class MajorTicksTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(MajorTicksType))
        End Function
    End Class
#End Region

#Region "MinorTicksType"
    Public Class MinorTicksType
        Private def_NumTicks As Integer = 5
        Private def_TickSize As Single = 6
        Private def_TickThickness As Integer = 1
        Private def_TickColor As Color = Color.Black

        Private _NumTicks As Integer = def_NumTicks
        Private _TickSize As Single = def_TickSize
        Private _TickColor As Color = def_TickColor
        Private _TickThickness As Integer = def_TickThickness

        'Public Events
        Public Event PropertyChanged(ByVal PropertyName As String)

        Public Sub New()

        End Sub

        <Description("Indicates the number of tick marks between each Major Tick. Set to 0 for none.")> _
        Public Property NumTicks() As Integer
            Get
                Return _NumTicks
            End Get
            Set(ByVal value As Integer)
                If value < 0 Then value = 0
                _NumTicks = value
                RaiseEvent PropertyChanged("NumTicks")
            End Set
        End Property
        Public Sub ResetNumTicks()
            Me.NumTicks = def_NumTicks
        End Sub
        Public Function ShouldSerializeNumTicks() As Boolean
            Return Not (NumTicks.Equals(def_NumTicks))
        End Function

        <Description("Determines the size of the lines used for the Minor Ticks.")> _
        Public Property TickSize() As Single
            Get
                Return _TickSize
            End Get
            Set(ByVal value As Single)
                If value < 0 Then value = 0
                _TickSize = value
                RaiseEvent PropertyChanged("TickSize")
            End Set
        End Property
        Public Sub ResetTickSize()
            Me.TickSize = def_TickSize
        End Sub
        Public Function ShouldSerializeTickSize() As Boolean
            Return Not (TickSize.Equals(def_TickSize))
        End Function

        <Description("The thickness of the lines used for the Minor Ticks.")> _
        Public Property TickThickness() As Integer
            Get
                Return _TickThickness
            End Get
            Set(ByVal value As Integer)
                If value < 0 Then value = 0
                _TickThickness = value
                RaiseEvent PropertyChanged("TickThickness")
            End Set
        End Property
        Public Sub ResetTickThickness()
            Me.TickThickness = def_TickThickness
        End Sub
        Public Function ShouldSerializeTickThickness() As Boolean
            Return Not (TickThickness.Equals(def_TickThickness))
        End Function

        <Description("The color of the lines used for the Minor Ticks.")> _
        Public Property TickColor() As Color
            Get
                Return _TickColor
            End Get
            Set(ByVal value As Color)
                _TickColor = value
                RaiseEvent PropertyChanged("TickColor")
            End Set
        End Property
        Public Sub ResetTickColor()
            Me.TickColor = def_TickColor
        End Sub
        Public Function ShouldSerializeTickColor() As Boolean
            Return Not (TickColor.Equals(def_TickColor))
        End Function


        Public Sub Reset()
            _NumTicks = def_NumTicks
            _TickSize = def_TickSize
            _TickThickness = def_TickThickness
            _TickColor = def_TickColor

            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If _NumTicks.Equals(def_NumTicks) _
                    AndAlso _TickSize.Equals(def_TickSize) _
                    AndAlso _TickThickness.Equals(def_TickThickness) _
                    AndAlso _TickColor.Equals(def_TickColor) Then
                Return False
            Else
                Return True
            End If
        End Function

        Public Overrides Function ToString() As String
            Return "(Minor Ticks Format)"
        End Function
    End Class
    Public Class MinorTicksTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(MinorTicksType))
        End Function
    End Class
#End Region

#Region "NeedleType"
    Public Class NeedleType
        Private def_CenterRadius As Single = 12
        Private def_CenterColor As Color = Color.Black
        Private def_PercentageLength As Single = 90
        Private def_Color As Color = Color.Blue
        Private def_Thickness As Single = 12

        Private _CenterRadius As Single = def_CenterRadius
        Private _CenterColor As Color = def_CenterColor
        Private _PercentageLength As Single = def_PercentageLength
        Private _Color As Color = def_Color
        Private _Thickness As Single = def_Thickness

        'Public Events
        Public Event PropertyChanged(ByVal PropertyName As String)

        Public Sub New()

        End Sub

        <Description("Defines the size of the needle center circle.")> _
        Public Property CenterRadius() As Single
            Get
                Return _CenterRadius
            End Get
            Set(ByVal value As Single)
                _CenterRadius = value
                RaiseEvent PropertyChanged("CenterRadius")
            End Set
        End Property
        Public Sub ResetCenterRadius()
            Me.CenterRadius = def_CenterRadius
        End Sub
        Public Function ShouldSerializeCenterRadius() As Boolean
            Return Not (CenterRadius.Equals(def_CenterRadius))
        End Function

        <Description("Defines the color of the needle center circle.")> _
        Public Property CenterColor() As Color
            Get
                Return _CenterColor
            End Get
            Set(ByVal value As Color)
                _CenterColor = value
                RaiseEvent PropertyChanged("CenterColor")
            End Set
        End Property
        Public Sub ReseCenterColor()
            Me.CenterColor = def_CenterColor
        End Sub
        Public Function ShouldSerializeCenterColor() As Boolean
            Return Not (CenterColor.Equals(def_CenterColor))
        End Function

        <Description("Defines the length of the needle as a percentage of the dial size.")> _
        Public Property PercentageLength() As Single
            Get
                Return _PercentageLength
            End Get
            Set(ByVal value As Single)
                If value > 100 Then value = 100
                If value < 1 Then value = 1
                _PercentageLength = value
                RaiseEvent PropertyChanged("PercentageLength")
            End Set
        End Property
        Public Sub ResetPercentageLength()
            Me.PercentageLength = def_PercentageLength
        End Sub
        Public Function ShouldSerializePercentageLength() As Boolean
            Return Not (PercentageLength.Equals(def_PercentageLength))
        End Function

        <Description("Defines the color of the gauge needle.")> _
        Public Property Color() As Color
            Get
                Return _Color
            End Get
            Set(ByVal value As Color)
                _Color = value
                RaiseEvent PropertyChanged("Color")
            End Set
        End Property
        Public Sub ResetColor()
            Me.Color = def_Color
        End Sub
        Public Function ShouldSerializColor() As Boolean
            Return Not (Color.Equals(def_Color))
        End Function

        <Description("Defines the thickness of the gauge needle at it's base.")> _
        Public Property Thickness() As Single
            Get
                Return _Thickness
            End Get
            Set(ByVal value As Single)
                If value < 1 Then value = 1
                _Thickness = value
                RaiseEvent PropertyChanged("Thickness")
            End Set
        End Property
        Public Sub ResetThickness()
            Me.Thickness = def_Thickness
        End Sub
        Public Function ShouldSerializeThickness() As Boolean
            Return Not (Thickness.Equals(def_Thickness))
        End Function

        Public Sub Reset()
            _CenterRadius = def_CenterRadius
            _CenterColor = def_CenterColor
            _PercentageLength = def_PercentageLength
            _Color = def_Color
            _Thickness = def_Thickness

            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If _CenterRadius.Equals(def_CenterRadius) _
                    AndAlso _CenterColor.Equals(def_CenterColor) _
                    AndAlso _PercentageLength.Equals(def_PercentageLength) _
                    AndAlso _Color.Equals(def_Color) _
                    AndAlso _Thickness.Equals(def_Thickness) Then
                Return False
            Else
                Return True
            End If
        End Function


        Public Overrides Function ToString() As String
            Return "(Needle Style)"
        End Function
    End Class
    Public Class NeedleTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(NeedleType))
        End Function
    End Class
#End Region
End Class

